#include <SFML/Graphics/Text.hpp>
#include <nice2d/application.h>
#include <nice2d/string.h>
#include <nice2d/components/fontmanager.h>
#include <nice2d/widgets/label.h>
#include <nice2d/widgets/desktop.h>

IMPLEMENT_OBJECT(LabelStyle, ControlStyle)

LabelStyle::LabelStyle()
{
    hoverBackground = normalBackground;
}

LabelStyle::~LabelStyle()
{
}

PTree LabelStyle::serialize()
{
    PTree node;
    node.add("style", toString(style));
    node.add_child("textColor", serializeObject(textColor));
    return node;
}

void LabelStyle::deserialize(const PTree &node)
{
    fontFile = node.get<std::string>("fontFile");
    characterSize = node.get<int32_t>("characterSize");
    style = fromString(node.get<std::string>("style"), sf::Text::Style::Regular);
    textColor = deserializeColor(node.get_child("textColor"));
}

void LabelStyle::sync()
{
}

class LabelData
{
public:
    LabelData(Label *thisLabel):
        label(thisLabel)
    {
        auto desktop = GET_APPLICATION_COMPONENT(Desktop);
        auto style = std::dynamic_pointer_cast<LabelStyle>(desktop->getControlStyle("Label"));
        label->setControlStyle(style);
        applySyle();
    }

    void applySyle()
    {
        auto style = std::dynamic_pointer_cast<LabelStyle>(label->getControlStyle());
        auto fontManager = GET_APPLICATION_COMPONENT(FontManager);

        auto font = fontManager->loadFromFile(style->fontFile);

        text.setFont(*font);
        text.setCharacterSize(style->characterSize);
        text.setStyle(style->style);

        if (textColor.has_value())
            text.setFillColor(textColor.value());
        else
            text.setFillColor(style->textColor);

        label->setBackground(style->normalBackground);
    }

    Label *label;
    sf::Text text;
    std::optional<sf::Color> textColor;
    HMode alignMode = HMode_Center;
};

IMPLEMENT_OBJECT(Label, Control)

Label::Label(const sf::Vector2f &size):
    Control(size),
    data(new LabelData(this))
{
}

Label::~Label()
{
}

void Label::setText(const sf::String &text)
{
    if (getText() != text) {
        data->text.setString(text);
        adjustText(data->text, getSize(), data->alignMode, getPadding());
        textChanged(text);
    }
}

sf::String Label::getText() const
{
    return data->text.getString();
}

void Label::setTextColor(const sf::Color &color)
{
    data->textColor = color;
    onStyleChanged();
}

sf::Color Label::getTextColor() const
{
    return data->text.getFillColor();
}

void Label::setAligment(HMode mode)
{
    data->alignMode = mode;
}

void Label::onDrawControl(sf::RenderTarget &target, sf::RenderStates states) const
{
    target.draw(data->text, states);
}

void Label::onPositionChanged()
{
    adjustText(data->text, getSize(), data->alignMode, 3.0f);
}

void Label::onStyleChanged()
{
    data->applySyle();
}
